#include "hunList.h"
#include <stdio.h>
#include <stdlib.h>
// ---- Private structure ----
// ----------------------------------------------------------------------------
typedef struct _listHead
{
   hunList *head;
   hunList *tail;
   int size;
} _listHead;
// ----------------------------------------------------------------------------
// ---- Private functions ----
hunList *_hunList_NewNode()
{
    return (hunList *)hunCalloc(sizeof(hunList));
}
// ----------------------------------------------------------------------------
void _hunList_FreeNode( hunList *node )
{
    hunFree(node);
}
// ----------------------------------------------------------------------------
_listHead *_listHeadCreate()
{
    return (_listHead *)hunCalloc(sizeof(_listHead));
}
// ----------------------------------------------------------------------------
hunList *_hunListCreateNewList()
{
    // create a new hunList
    hunList *headNode = _hunList_NewNode();
    // create a listhead
    _listHead *headData = _listHeadCreate();
    headData->head = headNode;
    headData->tail = headNode;
    headData->size = 0;

    headNode->data = headData;
    headNode->prev = headNode;
    headNode->next = headNode;
    
    return headNode;
}
// ----------------------------------------------------------------------------
// ---- Public functions ----
#define get_head(arg) (((_listHead *)arg->data)->head)
#define get_tail(arg) (((_listHead *)arg->data)->tail)
#define get_size(arg) (((_listHead *)arg->data)->size)

// ----------------------------------------------------------------------------
hunList *hunList_Front(hunList *list)
{
    return get_head(list);
}
// ----------------------------------------------------------------------------
hunList *hunList_Back(hunList *list)
{
    return get_tail(list);
}
// ----------------------------------------------------------------------------
hunList *hunList_PopFront(hunList *list)
{
    hunList *headNode = list->next;
    
    get_head(list) = headNode->next;

    list->next = headNode->next;

    // decrease size
    get_size(list) = get_size(list) - 1;
    return headNode;
}
// ----------------------------------------------------------------------------
hunList *hunList_PopBack(hunList *list)
{
    hunList *tailNode = ((_listHead *)list->data)->tail;

    get_tail(list) = tailNode->prev;
    
    get_tail(list)->next = NULL;
    
    // decrease size
    get_size(list) = get_size(list) - 1;
    return tailNode;
}
// ----------------------------------------------------------------------------
hunList *hunList_PushFront(hunList *list, void *data)
{
    if(!list)
        list = _hunListCreateNewList();
    // set item
    hunList *item = _hunList_NewNode();
    item->data = data;
    item->prev = list;
    item->next = list->next;

    // set list
    list->next = item;
    get_head(list) = item;

    // increase size
    get_size(list) = get_size(list) + 1;

    return list;

}
// ----------------------------------------------------------------------------
hunList *hunList_PushBack(hunList *list, void *data)
{
    if(!list)
        list = _hunListCreateNewList();
    // set item
    hunList *item = _hunList_NewNode();

    item->data = data;
    item->prev = get_tail(list);
    
    // set list
    get_tail(list)->next = item;
    if(get_size(list) == 0)
        get_head(list) = item;
    get_tail(list) = item;
    
    get_size(list) = get_size(list) + 1;

    return list;
}
// ----------------------------------------------------------------------------
hunList *hunList_Append(hunList *list, hunList *item)
{
    if(!item)
        return NULL;
    if(!list)
        list = _hunListCreateNewList();
    get_tail(list)->next = item;
    if(get_size(list) == 0)
        get_head(list) = item;
    get_tail(list) = item;
    get_size(list) = get_size(list) + 1;
    
    return list; 
}
// ----------------------------------------------------------------------------
int hunList_Find(hunList *list, void *data)
{
    int i;
    hunB("data = 0x%08X\n",data);
    if(!list)
        return -1;
    hunList *item = get_head(list);
    int size = get_size(list);
    for(i=0;i<size;++i)
    {
        if(item->data == data)
            return i;
        item = item->next;
    }
    return -1;
}
// ----------------------------------------------------------------------------
hunList *hunList_FindAll(hunList *list, void *data)
{
    int i;
    hunB("data = 0x%08X\n",data);
    if(!list)
        return NULL;
    hunList *item = get_head(list);
    hunList *newlist = NULL;
    int size = get_size(list);
    for(i=0;i<size;++i)
    {
        if(item->data == data)
        {
            newlist = hunList_PushBack(newlist, (void *)i);
        }
        item = item->next;
    }
    return newlist;
}
// ----------------------------------------------------------------------------
hunList *hunList_At(hunList *list, int num)
{
    if(!list)
        return NULL;
    int i;
    hunList *item = get_head(list);
    int size = get_size(list);
    if(num > size || num < 0)
        return NULL;
    for(i=0;i<num;++i)
        item=item->next;
    return item;
}
// ----------------------------------------------------------------------------
hunList *hunList_InsertData(hunList *list, int idx, void *data)
{
    if(!list)
        //list = _hunListCreateNewList();
        return NULL;
    
    hunList *prevItem = hunList_At(list, idx);
    if(!prevItem)
        return NULL;
    hunList *nextItem = hunList_At(list, idx+1);
    
    // set item
    hunList *item = _hunList_NewNode();

    if(get_size(list) == 0)
        get_head(list) = item;
    item->data = data;
    item->next = nextItem;
    item->prev = prevItem;

    // set list
    prevItem->next = item;
    if(nextItem)
        nextItem->prev = item;
    
    get_size(list) = get_size(list) + 1;

    return list;
}
// ----------------------------------------------------------------------------
hunBool hunList_RemoveByIdx(hunList *list, int idx)
{
    return hunTrue;
}
// ----------------------------------------------------------------------------
hunBool hunList_InsertByItem(hunList *list, hunList *item, void *data)
{
    return hunTrue;
}
// ----------------------------------------------------------------------------
hunBool hunList_RemoveByItem(hunList *list, int idx)
{
    return hunTrue;
}
// ----------------------------------------------------------------------------
int hunList_Size(hunList *list)
{
    return get_size(list);
}
// ----------------------------------------------------------------------------
void hunList_Reset(hunList *list)
{
    int i;
    int size = get_size(list);
    for(i=0;i<size;++i)
    {
        hunList *item = hunList_PopFront(list);
        hunG("free item data=%d\n", (int)item->data);
        hunFree( item );
    }
    hunFree(list->data);
    hunFree(list);
}
// ----------------------------------------------------------------------------
